//      bugmap.cpp
//      
//      Copyright 2012 dimir <dimir@dimir-pc>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.
//      
//      


#include "bugmap.h"


BugMap::BugMap()
{
	this->scorePlayer1 = 0;
	this->scorePlayer2 = 0;	
}
bool BugMap::Good(char c){
	if ( (c == '.') || (c == 'H') || 
		 (c == '#') || (c == '1') || 
		 (c == '2') ){
		return true;
	}else{
		return false;
	}
}

bool BugMap::loadMap(const std::string& Map){
		FILE* file_map = fopen(Map.c_str(), "r");
		for (int i = 0; i < 15; i++){
			for (int j = 0; j < 15; j++){
					char c = fgetc(file_map);
					if (!Good(c)) return false;
					this->map[i][j] = c;
			}
			char c = fgetc(file_map);
			if (c != '\n'){
				return false;
			}
			
		}
		for (int i = 0; i < 15; i++){
			for (int j = 0; j < 15; j++){
				if (!fscanf(file_map, "%d", bugs[i] + j))
				 return false;
			}
		}
		fclose(file_map);
	return true;

}

std::string BugMap::toString(){
	std::stringstream ss;
	for (int i = 0; i < 15; i++){
		for (int j = 0; j < 15; j++) ss << map[i][j];
		ss << '\n';
	}
	for (int i = 0; i < 15; i++){
		for (int j = 0; j < 15; j++){
			 ss << bugs[i][j];
			 if (j != 14) ss << ' ';
		}
		ss << '\n';
	}
	return ss.str();
};

void BugMap::reverseSide(){
	for (int i = 0; i < 15; i++){
		for (int j = 0; j < 15; j++)
			bugs[i][j] *= -1;
	};
	return ;
};

std::vector<Decree> BugMap::checkDecrees(const std::vector<Decree>& decrees){
	std::vector<Decree> result;
	int new_bugs[15][15];
	memcpy((void *)new_bugs, (void *)bugs, sizeof(bugs));
	int number_decree = decrees.size();
	for (int i = 0; i < number_decree; i++){
		if (checkDirectionOfDecree(decrees[i])){
			new_bugs[decrees[i].getRow()][decrees[i].getColumn()] -= decrees[i].getNumberBug();
		};
	}
	for (int i = 0; i < number_decree; i++){
		if (checkDirectionOfDecree(decrees[i])){
			if (new_bugs[decrees[i].getRow()][decrees[i].getColumn()] >= 0){
				result.push_back(decrees[i]);
			};
		};
	}
	return result;
}

bool BugMap::checkDirectionOfDecree(const Decree& decree){
	int i = decree.getRow();
	int j = decree.getColumn();
	if (i <0 || i > 14 || j < 0 || j > 14)
		return false;
	if (decree.getNumberBug() < 0){
		return false;
	}
	if (decree.getDirection()  < 0 || decree.getDirection() > 3){
		return false;
	}
	switch (decree.getDirection())
	{
		case LEFT:
			if (j > 0){
				if (map[i][j-1] != '#'){
					return true;
				}else{
					return false;
				};
			}else{
				return false;
			};			
			break;
		case UP:
			if (i > 0){
				if (map[i-1][j] != '#'){
					return true;
				}else{
					return false;
				};
			}else{
				return false;
			}
			break;
		case RIGHT:
			if (j < 14){
				if (map[i][j+1] != '#'){
					return true;
				}else{
					return false;
				}
			}else{
				return false;
			}
			break;
		case DOWN:
			if (i < 14){
				if (map[i+1][j] != '#'){
					return true;
				}else{
					return false;
				}
			}else{
				return false;
			}
			break;
		default:
			return false;
			
	}
	
}
u_int BugMap::update(std::vector<Decree>& decrees, const u_int& numberOfPlayer){
	int new_bugs[15][15];
	memset((void*)new_bugs, 0, sizeof(new_bugs));
	std::vector<Decree> good_decree = checkDecrees(decrees);
	
	//step 1
	//выполняем приказы, перемещаем жуков
	int n = good_decree.size();
	for (int k = 0; k < n; k++){
		int i = decrees[k].getRow();
		int j = decrees[k].getColumn();
		bugs[i][j] -= decrees[k].getNumberBug();
		switch (decrees[k].getDirection())
		{
			case LEFT:
				j--;
				break;
			case UP:
				i--;
				break;
			case RIGHT:
				j++;
				break;
			case DOWN:
				i++;
				break;
			default:;
		}
		new_bugs[i][j] += decrees[k].getNumberBug();		
	}
	//step 2
	//В гнёздах рождаются новые жуки
	for (int i = 0; i < 15; i++){
		for (int j = 0; j < 15; j++){
			if (map[i][j] == '1' || map[i][j] == '2'){
				if ( (map[i][j] - 48) == numberOfPlayer ){
					bugs[i][j]++;
				}else{
					bugs[i][j]--;
				}
				if (numberOfPlayer == 1){
					scorePlayer1++;
				}else{
					scorePlayer2++;
				}
			};
		};
	}
	
	//step 3, battle
	//Происходят все сражения
	for (int i = 0; i < 15; i++){
		for (int j = 0; j < 15; j++){
			if (new_bugs[i][j] && ( bugs[i][j] < 0)){
				int first = new_bugs[i][j];
				int second = -bugs[i][j];
				if (!battle(first, second)){
					//победил текущий игрок
					if (numberOfPlayer == 1){
						scorePlayer1 += (-bugs[i][j]);
					}else{
						scorePlayer2 += (-bugs[i][j]);
					}
					bugs[i][j] = first;
				}else{
					//победил вражеский игрок
					if (numberOfPlayer == 1){
						scorePlayer1 += (new_bugs[i][j]);
					}else{
						scorePlayer2 += (new_bugs[j][j]);
					}
					bugs[i][j] = -second;
				}
			}else if(new_bugs[i][j] && ( bugs[i][j] >= 0) ){
				bugs[i][j] += new_bugs[i][j];
			}
		}
	}	
	//step 4	
	//Меняются принадлежности гнёзд
	for (int i = 0; i < 15; i++){
		for (int j = 0; j < 15; j++){
			if ( (map[i][j] == '1') || (map[i][j] == '2')  || (map[i][j] == 'H') )
				if (bugs[i][j]){
					if (bugs[i][j] > 0){
						map[i][j] = ( (numberOfPlayer == 1)?'1':'2');
					}else{
						map[i][j] = ( (numberOfPlayer == 1)?'2':'1' );
					}
				}
				
		}
		
	}
	//step 5
	//Проверяем не выиграл ли кто-нибудь
	u_int EXIT_CODE = 0;
	if ((EXIT_CODE = isPlayerWin(numberOfPlayer)) != 0){
		if (getFlag(EXIT_CODE) == FIRST_WINS){
			setNumberScore(EXIT_CODE, this->scorePlayer1);
		}else if (getFlag(EXIT_CODE) == SECOND_WINS){
			setNumberScore(EXIT_CODE, this->scorePlayer2);
		}
		return EXIT_CODE;
	}
	
	reverseSide();
	return 0;
};
u_int BugMap::getScorePlayer1(){
	return scorePlayer1;
}

u_int BugMap::getScorePlayer2(){
	return scorePlayer2;
}

bool BugMap::battle(int& a, int& b){
	int bound;
	while (a && b){
		bound = rand()%(a+ b);
		if (bound < a){
			b--;
		}else{
			a--;
		}
	}
	if (a) return false;
		else return true;
};

//0 - играем дальше
//1 - выиграл первый игрок
//2 - выиграл второй игрок
//3 - ни одного жука на осталось на поле оО.
u_int BugMap::isPlayerWin(const u_int& number_player){
	//	 текущий и вражеский игроки
	bool first, second;
	first = second = true;
	for (int i = 0; i < 15; i ++){
		for (int j = 0; j < 15; j++)
			if (this->bugs[i][j] > 0){
				first = false;
			}else if(this->bugs[i][j] < 0){
				second = false;
			};
	}
	if (first && second) return 3;
	if (first){
		return (number_player%2) + 1;
	}else if (second){
		return number_player;
	}else return 0;
}
